package org.barad.architecture.analyzer.archpad.component;

import java.util.HashMap;

import org.apache.log4j.Logger;

import static org.barad.architecture.analyzer.archpad.util.Properties.PROPERTIES_FILE_NAME;

public class ComponentFactory {
	private Logger log;
	private static ComponentFactory instance;
	private HashMap<String, Class<?>> components; 

	private ComponentFactory() {
		log = Logger.getLogger(this.getClass());
	}

	/**
	 * Gets the instance of Component factory. If one
	 * does not exist it is created
	 * @return The ComponentFactory
	 */
	public static ComponentFactory getInstance() {
		if (instance == null) {
			instance = new ComponentFactory(); 
		}
		return instance;
	}

	/**
	 * Returns the numeric constraint solver instance. If such one
	 * does not exist it is created. The solver is a singleton 
	 * @return A numeric constraint solver
	 */
	public ArchPadComponent getComponentInstance(String className) {
		Class<?> clazz = components.get(className);
		if (clazz == null) { 
			clazz = getComponentClass(className);
			components.put(className, clazz);
		}  
		return (ArchPadComponent)getInstance(clazz);
	}

	/**
	 * Creates a new constraint solver instance
	 * @return New constraint solver instance
	 */
	private Class<?> getComponentClass(String className) {
		Class<?> clazz = null;
		try {
			clazz = Class.forName(className);
		} catch(ClassNotFoundException cnfe) {
			log.error("Component class '" + className + "' does not exist or is not specified in the properties file: " + PROPERTIES_FILE_NAME, cnfe);
		}
		return clazz;
	}

	/**
	 * Instantiates on object of a given class
	 * @param clazz The class
	 * @return Instance of the class, null if any exception 
	 * is thrown during the instantiation
	 */
	private Object getInstance(Class<?> clazz) {
		Object instance = null;
		try {
			instance = clazz.newInstance();
		} catch(InstantiationException ie) {
			log.error(ie);
		} catch (IllegalAccessException iae) {
			log.error(iae);
		}
		return instance;
	}

	public HashMap<String, Class<?>> getComponents() {
		return components;
	}

	public void setComponents(HashMap<String, Class<?>> components) {
		this.components = components;
	}
}
